/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { computed, Ref } from 'vue';
import {
    DataGridHeaderCell,
    HeaderCellStatus,
    UseColumn,
    UseDataView,
    UseDragColumn,
    UseColumnFilter,
    UseFilterHistory,
    UseFitColumn,
    UseGroupColumn,
    UseSidebar,
    UseSort,
    UseVirtualScroll,
    UseFilter
} from '../../composition/types';
import { useResize } from '../../composition/use-resize';
import { DataGridProps } from '../../data-grid.props';
import getHeaderCellHander from './data-grid-header-handler.component';
import getGridSettingsIconRender from '../settings/data-grid-settings-icon.component';

export default function (
    props: DataGridProps,
    gridContentRef: Ref<any>,
    leftFixedGridContentRef: Ref<any>,
    rightFixedGridContentRef: Ref<any>,
    useColumnComposition: UseColumn,
    useDataViewComposition: UseDataView,
    useDragColumnComposition: UseDragColumn,
    useColumnFilterComposition: UseColumnFilter,
    useFilterComposition: UseFilter,
    useFilterHistoryComposition: UseFilterHistory,
    useFitColumnComposition: UseFitColumn,
    useGroupColumnComposition: UseGroupColumn,
    useSidebarComposition: UseSidebar,
    useSortComposition: UseSort,
    useVirtualScrollComposition: UseVirtualScroll,
    viewPortWidth: Ref<number>
) {
    const { showRowCheckbox, showRowNumer, sidebarCornerCellStyle } = useSidebarComposition;
    const { columnContext, hasLeftFixedColumn, hasRightFixedColumn } = useColumnComposition;
    const { onClickColumnResizeBar, resizeHandleStyle, resizeOverlayStyle } = useResize(
        props,
        columnContext,
        useFitColumnComposition,
        useVirtualScrollComposition
    );
    const { gridHeaderColumnsStyle, leftFixedGridHeaderColumnsStyle, rightFixedGridHeaderColumnsStyle } = useVirtualScrollComposition;
    const { dragstart, dragenter, dragover, dragend } = useDragColumnComposition;

    const defaultColumnHeight = columnContext.value.defaultColumnWidth;
    const gridHeaderCellHeight = 32;
    const headerCellPositionMap = new Map<number, number>([[0, 0]]);

    function headerCellPosition(headerCell: DataGridHeaderCell, columnIndex: number): Record<string, any> {
        const headerCellPosition = headerCellPositionMap.get(columnIndex) || 0;
        const styleObject = {
            height: `${headerCell.depth * gridHeaderCellHeight}px`,
            left: `${headerCell.left}px`,
            top: `${(headerCell.layer - 1) * gridHeaderCellHeight}px`,
            width: `${headerCell.actualWidth}px`
        } as Record<string, any>;
        if (columnContext.value.headerDepth > 1) {
            styleObject['line-height'] = `${headerCell.depth * gridHeaderCellHeight}px`;
        }
        headerCellPositionMap.set(columnIndex + 1, headerCellPosition + (headerCell.actualWidth || defaultColumnHeight));
        return styleObject;
    }

    const headerRowClass = computed(() => {
        const classObject = {
            'fv-grid-header': true,
            'fv-grid-header-group-columns': columnContext.value.headerDepth > 1
        } as Record<string, boolean>;
        return classObject;
    });

    const headerRowStyle = computed(() => {
        const styleObject = {
            height: `${columnContext.value.headerDepth * gridHeaderCellHeight}px`
        } as Record<string, any>;
        return styleObject;
    });

    const shouldShowHeaderOperation = function (headerCell: DataGridHeaderCell) {
        return (
            (headerCell.status & HeaderCellStatus.sortable) === HeaderCellStatus.sortable ||
            (headerCell.status & HeaderCellStatus.filterable) === HeaderCellStatus.filterable
        );
    };

    const { renderHeaderCellHandler } = getHeaderCellHander(
        props,
        gridContentRef,
        leftFixedGridContentRef,
        rightFixedGridContentRef,
        useColumnComposition,
        useDataViewComposition,
        useColumnFilterComposition,
        useFilterComposition,
        useFilterHistoryComposition,
        useSortComposition,
        useVirtualScrollComposition
    );

    const shouldShowGridSettings = function (headerCell: DataGridHeaderCell) {
        return !!headerCell.showSetting;
    };

    const { renderGridSettingsIcon } = getGridSettingsIconRender(
        props,
        gridContentRef,
        viewPortWidth,
        useColumnComposition,
        useDataViewComposition,
        useFilterComposition,
        useFitColumnComposition,
        useSortComposition,
        useVirtualScrollComposition
    );

    function renderGridHeaderCell(headerCell: DataGridHeaderCell, headerCells: DataGridHeaderCell[], columnIndex: number) {
        return (
            <div
                class="fv-grid-header-cell"
                style={headerCellPosition(headerCell, columnIndex)}
                draggable="true"
                onDragstart={(payload: DragEvent) => dragstart(payload, headerCell, columnIndex)}
                onDragenter={(payload: DragEvent) => dragenter(payload, columnIndex)}
                onDragend={(payload: DragEvent) => dragend(payload, headerCell)}
                onDragover={(payload: DragEvent) => dragover(payload, columnIndex)}>
                <span class="fv-column-title">{headerCell.title}</span>
                {shouldShowHeaderOperation(headerCell) && renderHeaderCellHandler(headerCell, columnIndex, headerCells)}
                {shouldShowGridSettings(headerCell) && renderGridSettingsIcon()}
                {headerCell.resizable && (
                    <span
                        class="fv-column-resize-bar"
                        onMousedown={(payload: MouseEvent) => onClickColumnResizeBar(payload, headerCell.field)}></span>
                )}
            </div>
        );
    }

    function renderGridHeaderColumns(headerCells: DataGridHeaderCell[]): any[] {
        return headerCells.map((headerCell: DataGridHeaderCell, columnIndex: number) => {
            const headerCellsNodes = [];
            headerCellsNodes.push(renderGridHeaderCell(headerCell, headerCells, columnIndex));
            if (headerCell.children && headerCell.children.length) {
                const subHeaderCellNodes = renderGridHeaderColumns(headerCell.children);
                headerCellsNodes.push(...subHeaderCellNodes);
            }
            return headerCellsNodes;
        });
    }

    function renderGridHeaderLeftFixed() {
        return (
            <div class="fv-grid-header-left-fixed">
                <div class="fv-grid-header-columns" style={leftFixedGridHeaderColumnsStyle.value}>
                    {renderGridHeaderColumns(columnContext.value.leftHeaderColumns)}
                </div>
            </div>
        );
    }

    function renderGridHeaderRigthFixed() {
        return (
            <div class="fv-grid-header-right-fixed">
                <div class="fv-grid-header-columns" style={rightFixedGridHeaderColumnsStyle.value}>
                    {renderGridHeaderColumns(columnContext.value.rightHeaderColumns)}
                </div>
            </div>
        );
    }

    function renderGridSideBarCorner() {
        return (
            <div class="fv-grid-header-corner" style={sidebarCornerCellStyle.value}>
                {showRowCheckbox.value && (
                    <div class="custom-control custom-checkbox f-checkradio-single fv-grid-sidebar-row-checkbox">
                        <input id="sidebar_checkall" title="sidebar_checkall" type="checkbox" class="custom-control-input" />
                        <label class="custom-control-label" for="sidebar_checkall"></label>
                    </div>
                )}
                {showRowNumer.value && props.rowNumber?.heading}
            </div>
        );
    }

    function renderGridHeader() {
        return (
            <div class={headerRowClass.value} style={headerRowStyle.value}>
                {(showRowCheckbox.value || showRowNumer.value) && renderGridSideBarCorner()}
                {hasLeftFixedColumn.value && renderGridHeaderLeftFixed()}
                <div class="fv-grid-header-primary">
                    <div class="fv-grid-header-columns" style={gridHeaderColumnsStyle.value}>
                        {renderGridHeaderColumns(columnContext.value.primaryHeaderColumns)}
                    </div>
                </div>
                {hasRightFixedColumn.value && renderGridHeaderRigthFixed()}
            </div>
        );
    }

    function renderGridColumnResizeOverlay() {
        return (
            <>
                <div class="fv-datagrid-resize-overlay" style={resizeOverlayStyle.value}></div>
                <div class="fv-datagrid-resize-proxy" style={resizeHandleStyle.value}></div>
            </>
        );
    }

    return { renderGridHeader, renderGridColumnResizeOverlay };
}
